/*
 * Ganesa Copyright (C) 2008 Wim Crols <twimpiex@gnx.be>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License Version 3
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

package be.gnx.ganesa.application.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Vector;

import be.gnx.ganesa.application.event.FeatureCreatedListener;
import be.gnx.ganesa.application.model.feature.Arc;
import be.gnx.ganesa.application.model.feature.Image;
import be.gnx.ganesa.application.model.feature.Line;
import be.gnx.ganesa.application.model.feature.Node;
import be.gnx.ganesa.application.model.feature.Point;
import be.gnx.ganesa.application.model.feature.Polygon;
import be.gnx.ganesa.application.model.feature.Set;

public abstract class Layer {

  private boolean saved = true;

  private String name;

  protected Cuboid boundingBox = new Cuboid(new Coordinate(-(Math.PI / 2), -Math.PI, 0), new Coordinate(Math.PI / 2, Math.PI, 0));

  protected HashMap<Serializable, Point> points = new HashMap<Serializable, Point>();

  protected HashMap<Serializable, Node> nodes = new HashMap<Serializable, Node>();

  protected HashMap<Serializable, Arc> arcs = new HashMap<Serializable, Arc>();

  protected HashMap<Serializable, Line> lines = new HashMap<Serializable, Line>();

  protected HashMap<Serializable, Polygon> polygons = new HashMap<Serializable, Polygon>();

  protected HashMap<Serializable, Set> sets = new HashMap<Serializable, Set>();

  protected HashMap<Serializable, Image> images = new HashMap<Serializable, Image>();

  private List<Feature> selectedFeatures = new ArrayList<Feature>();

  protected Layer(String name, Cuboid boundingBox) {
    this.name = name;
    this.boundingBox = boundingBox;
  }

  public boolean isSaved() {
    return saved;
  }

  public String getName() {
    return name;
  }

  public Cuboid getBoundingBox() {
    return boundingBox;
  }

  public void setSaved(boolean saved) {
    this.saved = saved;
  }

  public void setName(String name) {
    this.name = name;
  }

  public Collection<Point> getPoints() {
    return points.values();
  }

  public Collection<Node> getNodes() {
    return nodes.values();
  }

  public Collection<Arc> getArcs() {
    return arcs.values();
  }

  public Point getPoint(Long id) {
    return nodes.get(id);
  }

  public Arc getArc(Long id) {
    return arcs.get(id);
  }

  public List<Feature> getSelectedFeatures() {
    return selectedFeatures;
  }

  public void setSelectedFeatures(List<Feature> selectedFeatures) {
    this.selectedFeatures = selectedFeatures;
  }

  public void addSelectedFeature(Feature selectedFeature) {
    selectedFeatures.add(selectedFeature);
  }

  public void removeSelectedFeature(Feature selectedFeature) {
    selectedFeatures.remove(selectedFeature);
  }

  public void clearSelectedFeatures() {
    selectedFeatures.clear();
  }

  public void deleteFeature(Feature feature) {
    HashMap featuresHashMap = null;
    if (feature instanceof Point) {
      featuresHashMap = points;
    }
    if (feature instanceof Node) {
      featuresHashMap = nodes;
    }
    if (feature instanceof Arc) {
      featuresHashMap = arcs;
    }
    if (feature instanceof Line) {
      featuresHashMap = lines;
    }
    if (feature instanceof Polygon) {
      featuresHashMap = polygons;
    }
    if (feature instanceof Set) {
      featuresHashMap = sets;
    }
    if (feature instanceof Image) {
      featuresHashMap = images;
    }
    if (featuresHashMap != null) {
      featuresHashMap.remove(feature.getIdentifier());
    }
    for (Feature partOfFeature : feature.getPartOfFeatures().values()) {
      partOfFeature.deleteFeature(feature);
    }
  }

  public Feature getNearestFeature(Coordinate coordinate) {
    Point point = new Point() {
      
    };
    point.setCoordinate(coordinate);
    Feature nearestFeature = null;
    for (Node node : nodes.values()) {
      if (nearestFeature == null) {
        nearestFeature = node;
      } else if (node.distance(point) < nearestFeature.distance(point)){
        nearestFeature = node;
      }
    }
    return nearestFeature;
  }

  /* event listeners */
  private Vector<FeatureCreatedListener> dataCreatedListeners = new Vector<FeatureCreatedListener>();

  public Vector<FeatureCreatedListener> getDataCreatedListeners() {
    return dataCreatedListeners;
  }

  public void addDataCreatedListener(FeatureCreatedListener dataCreatedListener) {
    if (dataCreatedListener == null) {
      throw new NullPointerException();
    } else {
      dataCreatedListeners.add(dataCreatedListener);
    }
  }

  public void removeDataCreatedListener(FeatureCreatedListener dataCreatedListener) {
    if (dataCreatedListener == null) {
      throw new NullPointerException();
    } else {
      dataCreatedListeners.remove(dataCreatedListener);
    }
  }

}
